/*
Copyright 2025 PerfXLab (Beijing) Technologies Co., Ltd.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#pragma once

#include "stdint.h"
#include "stdbool.h"

#ifdef __cplusplus
extern "C"
{
#endif

#define OpenSpB_MAX_NAME_LENGTH 128

    /**
     * @brief The usual return value of the OpenSparseBLAS methods
     */
    typedef enum
    {
        OpenSpB_success = 0,  ///< Indicates successful method execution
        OpenSpB_failure = 1,  ///< Indicates method execution failure
        OpenSpB_no_value = -1 ///< Using the extract related method, the zero element is not stored in the object and the value is returned.
    } OpenSpB_info;

    /**
     * @brief Built-in data types supported by OpenSparseBLAS
     */
    typedef enum
    {
        OpenSpB_null_type,
        OpenSpB_BOOL,   ///< in C: bool
        OpenSpB_INT8,   ///< in C: int8_t
        OpenSpB_INT16,  ///< in C: int16_t
        OpenSpB_INT32,  ///< in C: int32_t
        OpenSpB_INT64,  ///< in C: int64_t
        OpenSpB_UINT8,  ///< in C: uint8_t
        OpenSpB_UINT16, ///< in C: uint16_t
        OpenSpB_UINT32, ///< in C: uint32_t
        OpenSpB_UINT64, ///< in C: uint64_t
        OpenSpB_FP32,   ///< in C: float
        OpenSpB_FP64,   ///< in C: double
        OpenSpB_type_n
    } OpenSpB_type;

    /**
     * @brief Type of index objects used in OpenSparseBLAS
     * @details It define by :
     * @code{.c}
     * typedef unsigned long int OpenSpB_index;
     * @endcode
     * The range of valid values for a variable of type OpenSpB_index is [0, OpenSpB_index_max] where the largest index value permissible is defined with a macro, OpenSpB_index_max.
     */
    typedef int64_t OpenSpB_index;
    /**
     * @brief A method argument literal to indicate that all indices of an input array should be used.
     *
     */
    extern OpenSpB_index *OpenSpB_all;

/**
 * @brief The largest OpenSpB_index value permissible
 */
#define OpenSpB_index_max ((OpenSpB_index)0x0fffffffffffffff)

    /**
     * @brief OpenSpB_scalar_opaque
     */
    struct OpenSpB_scalar_opaque;

    /**
     * @brief One scalar which can store any OpenSpB_type element.
     */
    typedef struct OpenSpB_scalar_opaque *OpenSpB_scalar;

    /**
     * @brief OpenSpB_vector_opaque
     */
    struct OpenSpB_vector_opaque;

    /**
     * @brief One-dimensional collection of elements; can be sparse.
     */
    typedef struct OpenSpB_vector_opaque *OpenSpB_vector;

    /**
     * @brief A Null OpenSpB_vector
     * @details It is used for the mask argument to call a none-mask vxm or mxv operation.
     */
    extern OpenSpB_vector OpenSpB_vector_null;

    struct OpenSpB_matrix_opaque;
    /**
     * @brief Two-dimensional collection of elements; typically sparse.
     */
    typedef struct OpenSpB_matrix_opaque *OpenSpB_matrix;
    /**
     * @brief A Null OpenSpB_matrix
     * @details It is used for the mask argument to call a none-mask vxm, mxv or mxm operation.
     */
    extern OpenSpB_matrix OpenSpB_matrix_null;

    // TODO: Needs be called by users?
    typedef enum
    {
        OpenSpB_VNEC_D = 0,
        OpenSpB_VNEC_S = 1,
    } OpenSpB_VNEC_type;

    typedef struct OpenSpB_coord
    {
        int x;
        int y;
    } OpenSpB_coord;

    // TODO: Needs be called by users?
    typedef struct VNEC_D_FP32
    {
        OpenSpB_coord *thread_coord_start;
        OpenSpB_coord *thread_coord_end;
        int *ecr_indices;
        int *NEC_NUM;
        int **use_x_indices;
        float **ecr_xx_val;
        int *v_row_ptr;
        int *col_start;
        float *val_align;
    } VNEC_D_FP32;

    typedef struct csr_f32
    {
        float *nnz;
        int *col, *row_begin, *row_end;
        int *task_start;
        int *task_end;
    } csr_f32;
    typedef struct VNEC_S_FP32
    {
        /*
            ECR
        */
        int *NEC_NUM;
        int **use_x_indices;
        float **ecr_xx_val;
        /*
            vectorization
        */
        int *spvv16_len;
        int **tasks;
        struct csr_f32 reorder_mat;
    } VNEC_S_FP32;

    typedef struct VNEC_L
    {
        int num_merge_items;
        int items_per_thread;
        int *diagonal_start;
        int *diagonal_end;
        OpenSpB_coord *thread_coord_start;
        OpenSpB_coord *thread_coord_end;
        int *nz_indices;
    } VNEC_L;

    typedef struct VNEC_D_FP64
    {
        OpenSpB_coord *thread_coord_start;
        OpenSpB_coord *thread_coord_end;
        int *ecr_indices;
        int *NEC_NUM;
        int **use_x_indices;
        double **ecr_xx_val;
        int *v_row_ptr;
        int *col_start;
        double *val_align;
    } VNEC_D_FP64;

    typedef struct csr_f64
    {
        double *nnz;
        int *col, *row_begin, *row_end;
        int *task_start;
        int *task_end;
    } csr_f64;
    typedef struct VNEC_S_FP64
    {
        /*
            ECR
        */
        int *NEC_NUM;
        int **use_x_indices;
        double **ecr_xx_val;
        /*
            vectorization
        */
        int *spvv8_len;
        int **tasks;
        struct csr_f64 reorder_mat;
    } VNEC_S_FP64;

    /**
     * @brief Object options available for format setting
     *
     */
    typedef enum
    {
        OpenSpB_vector_format, ///< You can set the format of the vector
        OpenSpB_matrix_format  ///< You can set the format of the matrix
    } OpenSpB_option_field_ext;

    /**
     * @Available vector formats
     *
     */
    typedef enum
    {
        OpenSpB_dense = 0,            ///< Dense Format: All elements of the vector including the zero element are represented
        OpenSpB_sparse = 1,           ///< Sparse Format: The non-zero elements of the vector are represented
        OpenSpB_vector_no_format = -1 ///< format not defined (Now useless)
    } OpenSpB_vector_format_value_ext;

    /**
     * @Available matrix formats
     *
     */
    typedef enum
    {
        OpenSpB_csc = 0,              ///< CSR: compressed sparse row format
        OpenSpB_csr = 1,              ///< CSC: compressed sparse column format
        OpenSpB_matrix_no_format = -1 ///< format not defined (Now useless)
    } OpenSpB_matrix_format_value_ext;

    /**
     * @brief The argument of \link OpenSpB_Global_Option_set_ext \endlink
     *
     */
    typedef union
    {
        OpenSpB_vector_format_value_ext vector_format;
        OpenSpB_matrix_format_value_ext matrix_format;
    } OpenSpB_object_format_ext;

    typedef enum
    {
        OpenSpB_operation_transpose = 0,           ///< The transpose operation is selected.
        OpenSpB_operation_conjugate_transpose = 1, ///< The conjugate transpose operation is selected.
        OpenSpB_operation_non_transpose = -1       ///< The non-transpose operation is selected.
    } OpenSpB_operation_t;

    enum OpenSpB_conj_type {
        OPENSPBLAS_CONJ    = 191,
        OPENSPBLAS_NO_CONJ = 192
    };
    
    enum OpenSpB_base_type {
        OPENSPBLAS_ZERO_BASE = 221,
        OPENSPBLAS_ONE_BASE  = 222
    };
    
    enum OpenSpB_trans_type {
        OPENSPBLAS_NO_TRANS   = 111,
        OPENSPBLAS_TRANS      = 112,
        OPENSPBLAS_CONJ_TRANS = 113 
    };
    
    enum OpenSpB_order_type {
        OPENSPBLAS_ROWMAJOR = 101,
        OPENSPBLAS_COLMAJOR = 102 
    };
    
    enum OpenSpB_uplo_type
    {
        OPENSPBLAS_UPPER = 121,
        OPENSPBLAS_LOWER = 122
    };
    
    enum OpenSpB_status
    {
        OPENSPBLAS_STATUS_SUCCESS  = 0,
        OPENSPBLAS_STATUS_INVALID  = 1,   // 非法参数
        OPENSPBLAS_STATUS_SINGULAR = 2    // 对角缺失或为 0
    };

#ifdef __cplusplus
}
#endif
